﻿using DataWorks_Butterworth;
using DataWorks_Sqlite.MappingClass;
using DataWorks_Tools.BasicMethods;
using DataWorks_Tools.MappModals;
using DataWorks_Tools.MergeDetails;
using MatFileHandler;
using MathNet.Numerics.LinearAlgebra;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization.Formatters;
using System.Text;
using System.Threading.Tasks;
using static DataWorks_Tools.BasicMethods.ReadfromCSV;

namespace DataWorks_Tools.MatlabDetails
{
    public static class ModalPredictionProcess
    {
       
        /// <summary>
        /// 单个csv单个mat参数的小模型输出index的流程
        /// </summary>
        /// <param name="csv"></param>
        /// <param name="matfile"></param>
        /// <param name="lastvaluesorzeros"></param>
        /// <returns></returns>
        public static async Task<List<double>> GetIdxfromSmallModal(CSVImport csv, List<MatlabFileMappingModal> matfile, List<double[]> lastvaluesorzeros, int causalorder, int uncausalorder, ButterworthParaModal modal)
        {
            //存放迹的数组
            List<double> trlst = new List<double>();
            try
            {
                //小模型的输入通道名
                var sin = matfile?.Where(a => a.name == "select_input").FirstOrDefault()?.celllst;
                //小模型的输出通道名(真实数据)
                var sout = matfile?.Where(a => a.name == "select_output").FirstOrDefault()?.celllst;

                //读取mean和std
                var ancphimean = matfile?.Where(a => a.name == "anc_PHI_mean_set").FirstOrDefault();
                var ancphistd = matfile?.Where(a => a.name == "anc_PHI_std_set").FirstOrDefault();
                //读取theta的数据
                var anctheta = matfile?.Where(a => a.name == "anc_theta_set").FirstOrDefault();
                if (sin != null && sout != null && ancphimean != null && ancphistd != null && anctheta != null)
                {
                    //获得所需input多列通道的数据
                    var sinlist = (await csv.GetSpecifiedMultiColumnDataAsync(sin));
                    //获得所需output多列通道的真实数据且滤波
                    var reallist = (await csv.GetSpecifiedMultiColumnDataAsync(sout)).ExcuteButterworthFilter2DList(modal);
                    if (sinlist != null && reallist != null)
                    {
                        //把前一个最后50个数据添加到后一个csv数据中再滤波
                        await MergeDataAsync(lastvaluesorzeros, sinlist);
                        sinlist = sinlist.ExcuteButterworthFilter2DList(modal);
                        //转成double二维数组 2610
                        var sinarr = await sinlist.Listto2DArrayAsync();
                        //转成矩阵 2610
                        var sinmatrix = sinarr.ArrayColumnsToMatrix();
                        //Console.WriteLine(sinmatrix);
                        //生成PHI  2560
                        var phire = sinmatrix.Matrix2PHI(causalorder, uncausalorder).Listto2DArray().ArrayRowsToMatrix();
                        //Console.WriteLine(phire);
                        //把真实值转成double二维数组
                        var realarr = await reallist.Listto2DArrayAsync();
                        //把真实值转成矩阵 2560
                        var realmatrix = realarr.ArrayColumnsToMatrix();
                        if (ancphimean?.matrices?.Count == 1 && ancphistd?.matrices?.Count == 1)
                        {
                            //获得ancphimean和ancphistd的参数矩阵
                            var ancphimeanmatrix = ancphimean.matrices[0];
                            var ancphistdmatrix = ancphistd.matrices[0];
                            //这里循环的作用是计算不同小模型的mse，最后选择最小的那个
                            for (int j = 0; j < ancphimeanmatrix.RowCount; j++)
                            {
                                //取第j行的数据变为行向量
                                var meanrow = ancphimeanmatrix.Row(j);
                                //转为每行相同的矩阵
                                var meanmatrix = meanrow.VectorToMatrix(phire.RowCount);
                                //取第j行的数据变为行向量
                                var stdrow = ancphistdmatrix.Row(j);
                                //转为每行相同的矩阵
                                var stdmatrix = stdrow.VectorToMatrix(phire.RowCount);
                                //先减去mean矩阵
                                var submeanmatrix = phire - meanmatrix;
                                //点除
                                var stdmeanmatrix = submeanmatrix.PointwiseDivide(stdmatrix);
                                //创建一个1列的矩阵，元素都是1
                                var ones = Matrix<double>.Build.Dense(stdmeanmatrix.RowCount, 1, 1.0);
                                //合并矩阵，即是增广矩阵
                                var augmentedmatrix = stdmeanmatrix.Append(ones);
                                //phi与theta相乘算出预测值
                                var estmatrix = augmentedmatrix * anctheta?.matrices?[j];
                                //计算与真实值的差矩阵
                                var res = estmatrix - realmatrix;
                                //先res转置*res，再求所有对角线的和即为迹
                                var tr = (res.Transpose() * res).Trace();
                                trlst.Add(tr);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
           
            return trlst;
        }
        /// <summary>
        /// 利用小模型输出的idx来预测大模型的数据矩阵并输出
        /// </summary>
        /// <param name="csv"></param>
        /// <param name="matfile"></param>
        /// <param name="lastvaluesorzeros"></param>
        /// <param name="idx"></param>
        /// <param name="causalorder"></param>
        /// <param name="uncausalorder"></param>
        /// <returns></returns>
        public static async Task<Matrix<double>?> GetPredictDatafromBigModal(CSVImport csv, List<MatlabFileMappingModal> matfile, List<double[]> lastvaluesorzeros, List<double> mselst,int causalorder, int uncausalorder, ButterworthParaModal modal)
        {
            Matrix<double>? result = null;
            try
            {
                //大模型的输入通道名
                var tin = matfile?.Where(a => a.name == "train_input").FirstOrDefault()?.celllst;
                //大模型的输出通道名(真实数据)
                var tout = matfile?.Where(a => a.name == "train_output").FirstOrDefault()?.celllst;

                //读取mean和std
                var tarphimean = matfile?.Where(a => a.name == "tar_PHI_mean_set").FirstOrDefault();
                var tarphistd = matfile?.Where(a => a.name == "tar_PHI_std_set").FirstOrDefault();
                //读取theta的数据
                var tartheta = matfile?.Where(a => a.name == "tar_theta_set").FirstOrDefault();
                if (tin != null && tarphimean != null && tarphistd != null && tartheta != null)
                {
                    //获得所需input多列通道的数据
                    var tinlist = (await csv.GetSpecifiedMultiColumnDataAsync(tin));
                    if (tinlist != null)
                    {
                        //把前一个最后49个没有滤波过的数据添加到后一个csv数据中再滤波
                        await MergeDataAsync(lastvaluesorzeros, tinlist);
                        tinlist = tinlist.ExcuteButterworthFilter2DList(modal);
                        //转成double二维数组 2610
                        var tinarr = await tinlist.Listto2DArrayAsync();
                        //转成矩阵 2610
                        var tinmatrix = tinarr.ArrayColumnsToMatrix();
                        //生成PHI  2560
                        var phire = tinmatrix.Matrix2PHI(causalorder, uncausalorder).Listto2DArray().ArrayRowsToMatrix();
                        //Console.WriteLine(phire);
                        if (tarphimean?.matrices?.Count == 1 && tarphistd?.matrices?.Count == 1)
                        {
                            var idx = mselst.IndexOf(mselst.Min());
                            //获得ancphimean和ancphistd的参数矩阵
                            var tarphimeanmatrix = tarphimean.matrices[0];
                            var tarphistdmatrix = tarphistd.matrices[0];
                            //存放迹的数组
                            List<double> trlst = new List<double>();
                            //取第j行的数据变为行向量
                            var meanrow = tarphimeanmatrix.Row(idx);
                            //转为每行相同的矩阵
                            var meanmatrix = meanrow.VectorToMatrix(phire.RowCount);
                            //取第j行的数据变为行向量
                            var stdrow = tarphistdmatrix.Row(idx);
                            //转为每行相同的矩阵
                            var stdmatrix = stdrow.VectorToMatrix(phire.RowCount);
                            //先减去mean矩阵
                            var submeanmatrix = phire - meanmatrix;

                            //点除
                            var stdmeanmatrix = submeanmatrix.PointwiseDivide(stdmatrix);
                            //Console.WriteLine(stdmeanmatrix);
                            //创建一个1列的矩阵，元素都是1
                            var ones = Matrix<double>.Build.Dense(stdmeanmatrix.RowCount, 1, 1.0);
                            //合并矩阵，即是增广矩阵
                            var augmentedmatrix = stdmeanmatrix.Append(ones);
                            //phi与theta相乘算出预测值
                            result = augmentedmatrix * tartheta?.matrices?[idx];
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
            return result;
        }


        public static async Task<List<string>> YXHExcuteDataPredictionAsync(DataPredictModal row)
        {
            List<string> list = new List<string>();//专用于输出程序计算过程中的错误信息
            //先创建输出文件夹
            Directory.CreateDirectory(row.rdpath);
            //获得需要合并的源数据日期文件夹列表
            var ds = BasicFilesOperation.YXHGetProcessedDateDir(row.odpath, row.rdpath, row.datedir);
            if (ds != null)
            {
                if (ds.Length > 0)
                {
                    Stopwatch timer = new Stopwatch();
                    timer.Start();
                    var matfilelst = BasicFilesOperation.YXHGetAllextFiles(row.matfilepath, "*.mat");
                    if (row.matfilename == null)
                    {
                        list.Add($"mat文件名填写错误");
                        return list;
                    }
                    //筛选有对应名称的mat文件
                    matfilelst = matfilelst.YXHFilterFilesByName(row.matfilename.YXHRemoveSpace());
                    ButterworthParaModal modal = new ButterworthParaModal();
                    modal.lowpass = row.lowpass;
                    modal.usefilter = row.usefilter;
                    List<List<MatlabFileMappingModal>> matrices = new List<List<MatlabFileMappingModal>>();
                    //先把mat文件存放入list里，因为只需要读取一次即可
                    foreach (var matfile in matfilelst)
                    {
                        var mat = matfile.FullName.TransferMattoUnifiedModal();
                        if (mat != null)
                        {
                            matrices.Add(mat);
                        }
                    }
                    //一个个对日期文件夹进行操作
                    foreach (var d in ds)
                    {
                        //存放小模型选择的详细内容的csv目录列表（比如D:\TEST\modal\IM31_filter_EM_F\03_15）
                        List<string> matmsedir = new List<string>();
                        //为每个mat文件创建以mat文件名为名称的目录
                        foreach (var matfile in matfilelst)
                        {
                            var matdir = matfile.Name.Split('.')[0];
                            string msedir = Path.Combine(row.matfilepath, matdir, d.Name);
                            matmsedir.Add(msedir);
                            Directory.CreateDirectory(msedir);
                        }
                        //获得分类好的文件列表
                        var classifiedlist = MergeDetailsMethods.YXHGetClassifyFileListperFolder(d, mergetype.txt, 1, 1);
                        //根据分类好的文件列表来进行预测，不要一个一个文件的去预测了
                        if (classifiedlist != null && classifiedlist.Count > 0)
                        {
                            //先定义输出日期目录文件夹路径
                            string resultdirectorypath = Path.Combine(row.rdpath, d.Name);
                            DirectoryInfo root = new DirectoryInfo(resultdirectorypath);
                            //创建日期目录文件夹
                            if (!root.Exists)
                            {
                                root.Create();
                            }
                            //复制txt
                            //筛选所有txt并复制到目标文件夹下
                            var txtinfo = BasicFilesOperation.YXHGetAllextFiles(d.FullName, "*.txt");
                            foreach (var file in txtinfo)
                            {
                                var txtresultpath = Path.Combine(resultdirectorypath, file.Name);
                                file.CopyTo(txtresultpath, true);
                            }
                            //先循环有几个停车类别
                            for (int k = 0; k < classifiedlist.Count; k++)
                            {
                                //每个mat文件对应的小模型的添加值和表头
                                List<List<double[]>> smlst = new List<List<double[]>>();
                                List<List<double[]>> bglst = new List<List<double[]>>();
                                for (int i = 0; i < matfilelst.Length; i++)
                                {
                                    smlst.Add(new List<double[]>());
                                    bglst.Add(new List<double[]>());
                                }
                                //存放评估数据的路径，以每个类别为单位
                                List<string> estimatepath = new List<string>();
                                //存放评估的数据集，以每个类别为单位
                                List<List<List<string>>> estimatedata = new List<List<List<string>>>();
                                //模型有几个就有几个数据集
                                for (int i = 0; i < matfilelst.Length; i++)
                                {
                                    estimatedata.Add(new List<List<string>>());
                                }
                                var fileinfo = classifiedlist[k].filelist;
                                //再循环每个停车类别下的每个csv
                                //第一个循环是循环每个csv文件
                                for (int i = 0; i < fileinfo.Count; i++)
                                {
                                    //生成输出csv的全路径
                                    string resultpath = Path.Combine(root.FullName, fileinfo[i].Name);
                                    //获取csv的数据模型
                                    var csv = await ReadfromCSV.GetDatafromCSVAsync(fileinfo[i]);
                                    //转成double[][]
                                    var csvdatalst = await csv.lists.Listto2DArrayAsync();
                                    //转成矩阵,这是未滤波的原始矩阵
                                    var csvmatrix = csvdatalst.ArrayColumnsToMatrix();
                                    //这里选择原始文件名，否则会把所有名字改为小写和去N
                                    var headers = csv.originalheaders;
                                    //第二个循环是循环每个mat文件`
                                    for (int j = 0; j < matfilelst.Length; j++)
                                    {
                                        //var matrices = matfilelst[j].FullName.TransferMattoUnifiedModal();
                                        //获取小模型的输入通道名
                                        var sin = matrices?[j].Where(a => a.name == "select_input").FirstOrDefault()?.celllst;
                                        //获取大模型的输入通道名
                                        var tin = matrices?[j].Where(a => a.name == "train_input").FirstOrDefault()?.celllst;
                                        //大模型的输出通道名(真实数据)
                                        var tout = matrices?[j].Where(a => a.name == "train_output").FirstOrDefault()?.celllst;
                                        var train = matrices?[j].Where(a => a.name == "train_set").FirstOrDefault()?.celllst;
                                        //小模型小模型选择的详细内容的csv的标题行
                                        if (i == 0)
                                        {
                                            var fixheads = new List<string>() { "start_time", "end_time", "model_name" };
                                            fixheads.AddRange(train);
                                            estimatedata[j].Add(fixheads);

                                            //获得输出的小模型选择的详细内容文件路径
                                            var outputpath = MergeDetailsMethods.YXHGetCombinedFileName(fileinfo, matmsedir[j], mergetype.txt);
                                            //把每一个小模型
                                            estimatepath.Add(outputpath);
                                        }
                                        if (tout != null)
                                        {
                                            headers = headers.Concat(tout).ToArray();
                                        }
                                        //获得所需小模型input多列通道的数据不滤波
                                        var sinlist = (await ReadfromCSV.GetSpecifiedMultiColumnDataAsync(csv, sin));
                                        //获得所需大模型input多列通道的数据不滤波
                                        var tinlist = (await ReadfromCSV.GetSpecifiedMultiColumnDataAsync(csv, tin));
                                        if (matrices != null)
                                        {
                                            //定义一个mse的列表，存放mse
                                            List<double> mselst = new List<double>();
                                            //因为每一个mat文件输入输出通道都可能不一样，所以要把添加点数放在这里
                                            if (i == 0)
                                            {
                                                //这个是小模型的初始化添加0
                                                smlst[j] = await AddZeros(sin, row.causalorder - 1);
                                                //这个是大模型的初始化添加0
                                                bglst[j] = await AddZeros(tin, row.causalorder - 1);
                                                //获取最小mse的数组
                                                mselst = await GetIdxfromSmallModal(csv, matrices[j], smlst[j], row.causalorder, row.uncausalorder, modal);
                                                //然后再获得小模型所需多列通道的最后49个数据
                                                smlst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(sinlist, row.causalorder - 1);
                                                if (mselst.Count > 0)
                                                {
                                                    //获得一个csv一个mat文件大模型的预测数据
                                                    var rematrix = await GetPredictDatafromBigModal(csv, matrices[j], bglst[j], mselst, row.causalorder, row.uncausalorder, modal);
                                                    //如果是第一个，把前面49行数据替换成第50行数据
                                                    rematrix?.ReplaceRowsInPlace(row.causalorder);
                                                    //Console.WriteLine(rematrix);
                                                    //然后再获得大模型所需多列通道的最后49个数据
                                                    bglst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(tinlist, row.causalorder - 1);
                                                    if (rematrix != null)
                                                    {
                                                        //不停的合并预测的数据到原csv数据
                                                        csvmatrix = csvmatrix.Append(rematrix);

                                                    }
                                                    else
                                                    {
                                                        list.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetPredictDatafromBigModal");
                                                        return list;

                                                    }
                                                }
                                                else
                                                {
                                                    list.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetIdxfromSmallModal");
                                                    return list;
                                                }
                                            }
                                            //从第二个csv开始就需要前一个csv的数据了
                                            else
                                            {
                                                //获取最小mse的idx
                                                mselst = await GetIdxfromSmallModal(csv, matrices[j], smlst[j], row.causalorder, row.uncausalorder, modal);
                                                //然后再获得小模型所需多列通道的最后49个数据
                                                smlst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(sinlist, row.causalorder - 1);
                                                if (mselst.Count > 0)
                                                {
                                                    var rematrix = await GetPredictDatafromBigModal(csv, matrices[j], bglst[j], mselst, row.causalorder, row.uncausalorder, modal);
                                                 
                                                    //然后再获得大模型所需多列通道的最后49个数据给下一个csv用
                                                    bglst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(tinlist, row.causalorder - 1);
                                                    if (rematrix != null)
                                                    {
                                                        csvmatrix = csvmatrix.Append(rematrix);
                                                    }
                                                    else
                                                    {
                                                        list.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetPredictDatafromBigModal");
                                                        return list;
                                                    }
                                                }
                                            }
                                            //写入小模型选择的详细内容

                                            //获取最小的mse的idx
                                            var minidx = mselst.IndexOf(mselst.Min());
                                            //获得最小工况名
                                            var condition = train?[minidx];
                                            List<string> strList = new List<string>
                                            {
                                                (i*5).ToString(),
                                                ((i+1)*5).ToString(),
                                            };
                                            if (condition != null)
                                            {
                                                strList.Add(condition.ToString());
                                                mselst.ForEach(num => strList.Add(num.ToString()));
                                                estimatedata[j].Add(strList);
                                            }
                                            else
                                            {
                                                list.Add($"train_set找不到工况");
                                                return list;
                                            }
                                        }
                                        else
                                        {
                                            list.Add($"{matfilelst[j].Name}mat文件无法读取");
                                            return list;
                                        }
                                    }
                                    //Console.WriteLine(csvmatrix);
                                    //准备写入csv了,获取预测和原始信号的数据
                                    var predictcsvdata = csvmatrix.ToRowArrays();
                                    await CSVHelperClass.SaveCSVfromArrayData(predictcsvdata, headers, resultpath);
                                }
                                //写入评估csv
                                for (int i = 0; i < estimatepath.Count; i++)
                                {
                                    await CSVHelperClass.SaveCSVfromListStringData(estimatedata[i], estimatepath[i]);
                                }
                            }
                        }
                        else
                        {
                            list.Add("txt合并文件列表没有数据");
                            return list;
                        }
                    }
                    timer.Stop();
                    list.Add($"预测程序总完成时间为{timer.Elapsed.TotalMinutes.ToString("0.00")}分-单线程");

                }
                else
                {
                    list.Add("目标路径下已有所有数据，不进行任何操作");
                    return list;
                }
            }
            else
            {
                list.Add("目标路径有问题，请检查配置文件");
            }
            return list;
        }

        public static async Task<List<string>> YXHExcuteDataPredictionMultiThreadAsync(DataPredictModal row)
        {
            List<string> list = new List<string>();//专用于输出程序计算过程中的错误信息
            //先创建输出文件夹
            Directory.CreateDirectory(row.rdpath);
            //获得需要合并的源数据日期文件夹列表
            var ds = BasicFilesOperation.YXHGetProcessedDateDir(row.odpath, row.rdpath, row.datedir);
            if (ds != null)
            {
                if (ds.Length > 0)
                {
                    Stopwatch timer = new Stopwatch();
                    timer.Start();
                    var matfilelst = BasicFilesOperation.YXHGetAllextFiles(row.matfilepath, "*.mat");
                    if (row.matfilename == null)
                    {
                        list.Add($"mat文件名填写错误");
                        return list;
                    }
                    //筛选有对应名称的mat文件
                    matfilelst = matfilelst.YXHFilterFilesByName(row.matfilename.YXHRemoveSpace());
                    ButterworthParaModal modal = new ButterworthParaModal();
                    modal.lowpass = row.lowpass;
                    modal.usefilter = row.usefilter;
                    List<List<MatlabFileMappingModal>> matrices = new List<List<MatlabFileMappingModal>>();
                    //先把mat文件存放入list里，因为只需要读取一次即可
                    foreach (var matfile in matfilelst)
                    {
                        var mat = matfile.FullName.TransferMattoUnifiedModal();
                        if(mat != null)
                        {
                            matrices.Add(mat);
                        }
                    }
                    //一个个对日期文件夹进行操作
                    foreach (var d in ds)
                    {
                        Stopwatch Stimer = new Stopwatch();
                        Stimer.Start();
                        //存放小模型选择的详细内容的csv目录列表（比如D:\TEST\modal\IM31_filter_EM_F\03_15）
                        List<string> matmsedir = new List<string>();
                        //为每个mat文件创建以mat文件名为名称的目录
                        foreach (var matfile in matfilelst)
                        {
                            var matdir = matfile.Name.Split('.')[0];
                            string msedir = Path.Combine(row.matfilepath, matdir, d.Name);
                            matmsedir.Add(msedir);
                            Directory.CreateDirectory(msedir);
                        }
                        //获得分类好的文件列表
                        var classifiedlist = MergeDetailsMethods.YXHGetClassifyFileListperFolder(d, mergetype.txt, 1, 1);
                        //根据分类好的文件列表来进行预测，不要一个一个文件的去预测了
                        if (classifiedlist != null && classifiedlist.Count > 0)
                        {
                            //先定义输出日期目录文件夹路径
                            string resultdirectorypath = Path.Combine(row.rdpath, d.Name);
                            DirectoryInfo root = new DirectoryInfo(resultdirectorypath);
                            //创建日期目录文件夹
                            if (!root.Exists)
                            {
                                root.Create();
                            }
                            //复制txt
                            //筛选所有txt并复制到目标文件夹下
                            var txtinfo = BasicFilesOperation.YXHGetAllextFiles(d.FullName, "*.txt");
                            foreach (var file in txtinfo)
                            {
                                var txtresultpath = Path.Combine(resultdirectorypath, file.Name);
                                file.CopyTo(txtresultpath, true);
                            }
                            //准备多线程
                            List<Task<List<string>>> tasks = new List<Task<List<string>>>();
                            foreach (var part in classifiedlist)
                            {
                                Task <List<string>> task = Task.Run(async () =>
                                {
                                    List<string> result = new List<string>();
                                    //每个mat文件对应的小模型的添加值和表头
                                    List<List<double[]>> smlst = new List<List<double[]>>();
                                    List<List<double[]>> bglst = new List<List<double[]>>();
                                    for (int i = 0; i < matfilelst.Length; i++)
                                    {
                                        smlst.Add(new List<double[]>());
                                        bglst.Add(new List<double[]>());
                                    }
                                    //存放评估数据的路径，以每个类别为单位
                                    List<string> estimatepath = new List<string>();
                                    //存放评估的数据集，以每个类别为单位
                                    List<List<List<string>>> estimatedata = new List<List<List<string>>>();
                                    //模型有几个就有几个数据集
                                    for (int i = 0; i < matfilelst.Length; i++)
                                    {
                                        estimatedata.Add(new List<List<string>>());
                                    }
                                    var fileinfo = part.filelist;
                                    //再循环每个停车类别下的每个csv
                                    //第一个循环是循环每个csv文件
                                    for (int i = 0; i < fileinfo.Count; i++)
                                    {
                                        //生成输出csv的全路径
                                        string resultpath = Path.Combine(root.FullName, fileinfo[i].Name);
                                        //获取csv的数据模型
                                        var csv = await ReadfromCSV.GetDatafromCSVAsync(fileinfo[i]);
                                        //转成double[][]
                                        var csvdatalst = await csv.lists.Listto2DArrayAsync();
                                        //转成矩阵,这是未滤波的原始矩阵
                                        var csvmatrix = csvdatalst.ArrayColumnsToMatrix();
                                        //这里选择原始文件名，否则会把所有名字改为小写和去N
                                        var headers = csv.originalheaders;
                                        //第二个循环是循环每个mat文件`
                                        for (int j = 0; j < matfilelst.Length; j++)
                                        {
                                            //var matrices = matfilelst[j].FullName.TransferMattoUnifiedModal();
                                            //获取小模型的输入通道名
                                            var sin = matrices?[j].Where(a => a.name == "select_input").FirstOrDefault()?.celllst;
                                            //获取大模型的输入通道名
                                            var tin = matrices?[j].Where(a => a.name == "train_input").FirstOrDefault()?.celllst;
                                            //大模型的输出通道名(真实数据)
                                            var tout = matrices?[j].Where(a => a.name == "train_output").FirstOrDefault()?.celllst;
                                            var train = matrices?[j].Where(a => a.name == "train_set").FirstOrDefault()?.celllst;
                                            //小模型小模型选择的详细内容的csv的标题行
                                            if (i == 0)
                                            {
                                                var fixheads = new List<string>() { "start_time", "end_time", "model_name" };
                                                fixheads.AddRange(train);
                                                estimatedata[j].Add(fixheads);

                                                //获得输出的小模型选择的详细内容文件路径
                                                var outputpath = MergeDetailsMethods.YXHGetCombinedFileName(fileinfo, matmsedir[j], mergetype.txt);
                                                //把每一个小模型
                                                estimatepath.Add(outputpath);
                                            }
                                            if (tout != null)
                                            {
                                                headers = headers.Concat(tout).ToArray();
                                            }
                                            //获得所需小模型input多列通道的数据不滤波
                                            var sinlist = (await ReadfromCSV.GetSpecifiedMultiColumnDataAsync(csv, sin));
                                            //获得所需大模型input多列通道的数据不滤波
                                            var tinlist = (await ReadfromCSV.GetSpecifiedMultiColumnDataAsync(csv, tin));
                                            if (matrices?[j] != null)
                                            {
                                                //定义一个mse的列表，存放mse
                                                List<double> mselst = new List<double>();
                                                //因为每一个mat文件输入输出通道都可能不一样，所以要把添加点数放在这里
                                                if (i == 0)
                                                {
                                                    //这个是小模型的初始化添加0
                                                    smlst[j] = await AddZeros(sin, row.causalorder - 1);
                                                    //这个是大模型的初始化添加0
                                                    bglst[j] = await AddZeros(tin, row.causalorder - 1);
                                                    //获取最小mse的数组
                                                    mselst = await GetIdxfromSmallModal(csv, matrices[j], smlst[j], row.causalorder, row.uncausalorder, modal);
                                                    //然后再获得小模型所需多列通道的最后49个数据
                                                    smlst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(sinlist, row.causalorder - 1);
                                                    if (mselst.Count > 0)
                                                    {
                                                        //获得一个csv一个mat文件大模型的预测数据
                                                        var rematrix = await GetPredictDatafromBigModal(csv, matrices[j], bglst[j], mselst, row.causalorder, row.uncausalorder, modal);
                                                        //如果是第一个，把前面49行数据替换成第50行数据
                                                        rematrix?.ReplaceRowsInPlace(row.causalorder);
                                                        //然后再获得大模型所需多列通道的最后49个数据
                                                        bglst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(tinlist, row.causalorder - 1);
                                                        if (rematrix != null)
                                                        {
                                                            //不停的合并预测的数据到原csv数据
                                                            csvmatrix = csvmatrix.Append(rematrix);

                                                        }
                                                        else
                                                        {
                                                            result.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetPredictDatafromBigModal");
                                                            return result;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        list.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetIdxfromSmallModal");
                                                        return result;
                                                    }
                                                }
                                                //从第二个csv开始就需要前一个csv的数据了
                                                else
                                                {
                                                    //获取最小mse的idx
                                                    mselst = await GetIdxfromSmallModal(csv, matrices[j], smlst[j], row.causalorder, row.uncausalorder, modal);
                                                    //然后再获得小模型所需多列通道的最后49个数据
                                                    smlst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(sinlist, row.causalorder - 1);
                                                    if (mselst.Count > 0)
                                                    {
                                                        var rematrix = await GetPredictDatafromBigModal(csv, matrices[j], bglst[j], mselst, row.causalorder, row.uncausalorder, modal);
                                                        //然后再获得大模型所需多列通道的最后49个数据给下一个csv用
                                                        bglst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(tinlist, row.causalorder - 1);
                                                        if (rematrix != null)
                                                        {
                                                            csvmatrix = csvmatrix.Append(rematrix);
                                                        }
                                                        else
                                                        {
                                                            list.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetPredictDatafromBigModal");
                                                            return result;
                                                        }
                                                    }
                                                }
                                                //写入小模型选择的详细内容

                                                //获取最小的mse的idx
                                                var minidx = mselst.IndexOf(mselst.Min());
                                                //获得最小工况名
                                                var condition = train?[minidx];
                                                List<string> strList = new List<string>
                                            {
                                                (i*5).ToString(),
                                                ((i+1)*5).ToString(),
                                            };
                                                if (condition != null)
                                                {
                                                    strList.Add(condition.ToString());
                                                    mselst.ForEach(num => strList.Add(num.ToString()));
                                                    estimatedata[j].Add(strList);
                                                }
                                                else
                                                {
                                                    list.Add($"train_set找不到工况");
                                                }
                                            }
                                            else
                                            {
                                                list.Add($"{matfilelst[j].Name}mat文件无法读取");
                                                return list;
                                            }
                                        }
                                        //准备写入csv了,获取预测和原始信号的数据
                                        var predictcsvdata = csvmatrix.ToRowArrays();
                                        await CSVHelperClass.SaveCSVfromArrayData(predictcsvdata, headers, resultpath);
                                    }
                                    //写入评估csv
                                    for (int i = 0; i < estimatepath.Count; i++)
                                    {
                                        await CSVHelperClass.SaveCSVfromListStringData(estimatedata[i], estimatepath[i]);
                                    }
                                    return result;
                                });
                                tasks.Add(task);
                            }
                            await Task.WhenAll(tasks.ToArray());
                            foreach (var task in tasks)
                            {
                                list.AddRange(task.Result);
                            }
                        }
                        else
                        {
                            list.Add("txt合并文件列表没有数据");
                            return list;
                        }
                        Stimer.Stop();
                        list.Add($"{d.Name}预测完成时间为{Stimer.Elapsed.TotalMinutes:0.00}分");
                    }
                    timer.Stop();
                    list.Add($"预测程序总完成时间为{timer.Elapsed.TotalMinutes.ToString("0.00")}分");

                }
                else
                {
                    list.Add("目标路径下已有所有数据，不进行任何操作");
                    return list;
                }
            }
            else
            {
                list.Add("目标路径有问题，请检查配置文件");
            }
            return list;
        }

        /// <summary>
        /// 限制多线程数量为4
        /// </summary>
        /// <param name="row"></param>
        /// <returns></returns>
        public static async Task<List<string>> YXHExcuteDataPredictionMultiThreadLimitedAsync(DataPredictModal row)
        {
            //await Console.Out.WriteLineAsync($"执行方法：YXHExcuteDataPredictionMultiThreadLimitedAsync，参数为{row}");
            List<string> list = new List<string>();//专用于输出程序计算过程中的错误信息
            //先创建输出文件夹
            Directory.CreateDirectory(row.rdpath);
            //获得需要合并的源数据日期文件夹列表
            var ds = BasicFilesOperation.YXHGetProcessedDateDir(row.odpath, row.rdpath, row.datedir);
            if (ds != null)
            {
                if (ds.Length > 0)
                {
                    Stopwatch timer = new Stopwatch();
                    timer.Start();
                    var matfilelst = BasicFilesOperation.YXHGetAllextFiles(row.matfilepath, "*.mat");
                    if (row.matfilename == null)
                    {
                        list.Add($"mat文件名填写错误");
                        return list;
                    }
                    //筛选有对应名称的mat文件
                    matfilelst = matfilelst.YXHFilterFilesByName(row.matfilename.YXHRemoveSpace());
                    ButterworthParaModal modal = new ButterworthParaModal();
                    modal.lowpass = row.lowpass;
                    modal.usefilter = row.usefilter;
                    List<List<MatlabFileMappingModal>> matrices = new List<List<MatlabFileMappingModal>>();
                    //先把mat文件存放入list里，因为只需要读取一次即可
                    foreach (var matfile in matfilelst)
                    {
                        var mat = matfile.FullName.TransferMattoUnifiedModal();
                        if (mat?.Count>0)
                        {
                            matrices.Add(mat);
                        }
                        else
                        {
                            list.Add($"mat文件读取错误");
                            return list;
                        }
                    }
                    //一个个对日期文件夹进行操作
                    foreach (var d in ds)
                    {
                        Stopwatch Stimer = new Stopwatch();
                        Stimer.Start();
                        //存放小模型选择的详细内容的csv目录列表（比如D:\TEST\modal\IM31_filter_EM_F\03_15）
                        List<string> matmsedir = new List<string>();
                        //为每个mat文件创建以mat文件名为名称的目录
                        foreach (var matfile in matfilelst)
                        {
                            var matdir = matfile.Name.Split('.')[0];
                            string msedir = Path.Combine(row.matfilepath, matdir, d.Name);
                            matmsedir.Add(msedir);
                            Directory.CreateDirectory(msedir);
                        }
                        //获得分类好的文件列表
                        var classifiedlist = MergeDetailsMethods.YXHGetClassifyFileListperFolder(d, mergetype.txt, 1, 1);
                        //根据分类好的文件列表来进行预测，不要一个一个文件的去预测了
                        if (classifiedlist != null && classifiedlist.Count > 0)
                        {
                            //先定义输出日期目录文件夹路径
                            string resultdirectorypath = Path.Combine(row.rdpath, d.Name);
                            DirectoryInfo root = new DirectoryInfo(resultdirectorypath);
                            //创建日期目录文件夹
                            if (!root.Exists)
                            {
                                root.Create();
                            }
                            //复制txt
                            //筛选所有txt并复制到目标文件夹下
                            var txtinfo = BasicFilesOperation.YXHGetAllextFiles(d.FullName, "*.txt");
                            foreach (var file in txtinfo)
                            {
                                var txtresultpath = Path.Combine(resultdirectorypath, file.Name);
                                file.CopyTo(txtresultpath, true);
                            }
                            //准备多线程
                            List<Task<List<string>>> tasks = new List<Task<List<string>>>();
                            //限制多线程数量
                            var semaphore = new SemaphoreSlim(row.threads);

                            foreach (var part in classifiedlist)
                            {
                                Task<List<string>> task = Task.Run(async () =>
                                {
                                    await semaphore.WaitAsync();// 等待信号量
                                    List<string> result = new List<string>();
                                    try
                                    {
                                        //每个mat文件对应的小模型的添加值和表头
                                        List<List<double[]>> smlst = new List<List<double[]>>();
                                        List<List<double[]>> bglst = new List<List<double[]>>();
                                        for (int i = 0; i < matfilelst.Length; i++)
                                        {
                                            smlst.Add(new List<double[]>());
                                            bglst.Add(new List<double[]>());
                                        }
                                        //存放评估数据的路径，以每个类别为单位
                                        List<string> estimatepath = new List<string>();
                                        //存放评估的数据集，以每个类别为单位
                                        List<List<List<string>>> estimatedata = new List<List<List<string>>>();
                                        //模型有几个就有几个数据集
                                        for (int i = 0; i < matfilelst.Length; i++)
                                        {
                                            estimatedata.Add(new List<List<string>>());
                                        }
                                        var fileinfo = part.filelist;
                                        //再循环每个停车类别下的每个csv
                                        //第一个循环是循环每个csv文件
                                        for (int i = 0; i < fileinfo.Count; i++)
                                        {
                                            //生成输出csv的全路径
                                            string resultpath = Path.Combine(root.FullName, fileinfo[i].Name);
                                            //获取csv的数据模型
                                            var csv = await ReadfromCSV.GetDatafromCSVAsync(fileinfo[i]);
                                            //先判断是否有无法转为数字的情况并输出
                                            if (!csv.Iscontinue)
                                            {
                                                list.Add($"{csv.errorname}列第{csv.errorrow}行无法转换为数字");
                                                return list;
                                            }
                                            //转成double[][]
                                            var csvdatalst = await csv.lists.Listto2DArrayAsync();
                                            //转成矩阵,这是未滤波的原始矩阵
                                            var csvmatrix = csvdatalst.ArrayColumnsToMatrix();
                                            //这里选择原始文件名，否则会把所有名字改为小写和去N
                                            var headers = csv.originalheaders;
                                            //第二个循环是循环每个mat文件`
                                            for (int j = 0; j < matfilelst.Length; j++)
                                            {
                                                //var matrices = matfilelst[j].FullName.TransferMattoUnifiedModal();
                                                //获取小模型的输入通道名
                                                var sin = matrices?[j].Where(a => a.name == "select_input").FirstOrDefault()?.celllst;
                                                //获取大模型的输入通道名
                                                var tin = matrices?[j].Where(a => a.name == "train_input").FirstOrDefault()?.celllst;
                                                //大模型的输出通道名(真实数据)
                                                var tout = matrices?[j].Where(a => a.name == "train_output").FirstOrDefault()?.celllst;
                                                var train = matrices?[j].Where(a => a.name == "train_set").FirstOrDefault()?.celllst;
                                                //小模型小模型选择的详细内容的csv的标题行
                                                if (i == 0)
                                                {
                                                    var fixheads = new List<string>() { "start_time", "end_time", "model_name" };
                                                    fixheads.AddRange(train);
                                                    estimatedata[j].Add(fixheads);

                                                    //获得输出的小模型选择的详细内容文件路径
                                                    var outputpath = MergeDetailsMethods.YXHGetCombinedFileName(fileinfo, matmsedir[j], mergetype.txt);
                                                    //把每一个小模型
                                                    estimatepath.Add(outputpath);
                                                }
                                                if (tout != null)
                                                {
                                                    headers = headers.Concat(tout).ToArray();
                                                }
                                                //获得所需小模型input多列通道的数据不滤波
                                                var sinlist = (await ReadfromCSV.GetSpecifiedMultiColumnDataAsync(csv, sin));
                                                //获得所需大模型input多列通道的数据不滤波
                                                var tinlist = (await ReadfromCSV.GetSpecifiedMultiColumnDataAsync(csv, tin));
                                                if (matrices?[j] != null)
                                                {
                                                    //定义一个mse的列表，存放mse
                                                    List<double> mselst = new List<double>();
                                                    //因为每一个mat文件输入输出通道都可能不一样，所以要把添加点数放在这里
                                                    if (i == 0)
                                                    {
                                                        //这个是小模型的初始化添加0
                                                        smlst[j] = await AddZeros(sin, row.causalorder - 1);
                                                        //这个是大模型的初始化添加0
                                                        bglst[j] = await AddZeros(tin, row.causalorder - 1);
                                                        //获取最小mse的数组
                                                        mselst = await GetIdxfromSmallModal(csv, matrices[j], smlst[j], row.causalorder, row.uncausalorder, modal);
                                                        //然后再获得小模型所需多列通道的最后49个数据
                                                        smlst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(sinlist, row.causalorder - 1);
                                                        if (mselst.Count > 0)
                                                        {
                                                            //获得一个csv一个mat文件大模型的预测数据
                                                            var rematrix = await GetPredictDatafromBigModal(csv, matrices[j], bglst[j], mselst, row.causalorder, row.uncausalorder, modal);
                                                            //如果是第一个，把前面49行数据替换成第50行数据
                                                            rematrix?.ReplaceRowsInPlace(row.causalorder);
                                                            //然后再获得大模型所需多列通道的最后49个数据
                                                            bglst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(tinlist, row.causalorder - 1);
                                                            if (rematrix != null)
                                                            {
                                                                //不停的合并预测的数据到原csv数据
                                                                csvmatrix = csvmatrix.Append(rematrix);

                                                            }
                                                            else
                                                            {
                                                                result.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetPredictDatafromBigModal");
                                                                return result;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            list.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetIdxfromSmallModal");
                                                            return result;
                                                        }
                                                    }
                                                    //从第二个csv开始就需要前一个csv的数据了
                                                    else
                                                    {
                                                        //获取最小mse的idx
                                                        mselst = await GetIdxfromSmallModal(csv, matrices[j], smlst[j], row.causalorder, row.uncausalorder, modal);
                                                        //然后再获得小模型所需多列通道的最后49个数据
                                                        smlst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(sinlist, row.causalorder - 1);
                                                        if (mselst.Count > 0)
                                                        {
                                                            var rematrix = await GetPredictDatafromBigModal(csv, matrices[j], bglst[j], mselst, row.causalorder, row.uncausalorder, modal);
                                                            //然后再获得大模型所需多列通道的最后49个数据给下一个csv用
                                                            bglst[j] = await ReadfromCSV.GetLastCausalOrderMultiChansAsync(tinlist, row.causalorder - 1);
                                                            if (rematrix != null)
                                                            {
                                                                csvmatrix = csvmatrix.Append(rematrix);
                                                            }
                                                            else
                                                            {
                                                                list.Add($"{matfilelst[j].Name}mat文件参数有问题,出错方法为: ModalPredictionProcess.GetPredictDatafromBigModal");
                                                                return result;
                                                            }
                                                        }
                                                    }
                                                    //写入小模型选择的详细内容

                                                    //获取最小的mse的idx
                                                    var minidx = mselst.IndexOf(mselst.Min());
                                                    //获得最小工况名
                                                    var condition = train?[minidx];
                                                    List<string> strList = new List<string>
                                            {
                                                (i*5).ToString(),
                                                ((i+1)*5).ToString(),
                                            };
                                                    if (condition != null)
                                                    {
                                                        strList.Add(condition.ToString());
                                                        mselst.ForEach(num => strList.Add(num.ToString()));
                                                        estimatedata[j].Add(strList);
                                                    }
                                                    else
                                                    {
                                                        list.Add($"train_set找不到工况");
                                                    }
                                                }
                                                else
                                                {
                                                    list.Add($"{matfilelst[j].FullName}mat文件无法读取");
                                                    return list;
                                                }
                                            }
                                            //准备写入csv了,获取预测和原始信号的数据
                                            var predictcsvdata = csvmatrix.ToRowArrays();
                                            await CSVHelperClass.SaveCSVfromArrayData(predictcsvdata, headers, resultpath);
                                        }
                                        //写入评估csv
                                        for (int i = 0; i < estimatepath.Count; i++)
                                        {
                                            await CSVHelperClass.SaveCSVfromListStringData(estimatedata[i], estimatepath[i]);
                                        }
                                        return result;
                                    }
                                    finally 
                                    {
                                        semaphore.Release(); // 释放信号量
                                    }
                                   
                                });
                                tasks.Add(task);
                            }
                            await Task.WhenAll(tasks.ToArray());
                            foreach (var task in tasks)
                            {
                                list.AddRange(task.Result);
                            }
                        }
                        else
                        {
                            list.Add("txt合并文件列表没有数据");
                            return list;
                        }
                        Stimer.Stop();
                        list.Add($"{d.Name}预测完成时间为{Stimer.Elapsed.TotalMinutes:0.00}分");
                    }
                    timer.Stop();
                    list.Add($"预测程序总完成时间为{timer.Elapsed.TotalMinutes.ToString("0.00")}分-多线程");

                }
                else
                {
                    list.Add("目标路径下已有所有数据，不进行任何操作");
                    return list;
                }
            }
            else
            {
                list.Add("目标路径有问题，请检查配置文件");
            }
            return list;
        }
    }
}



